typedef struct _GtkStyleProviderData GtkStyleProviderData;
struct _GtkStyleCascadeIter {
- int parent_index; /* pointing at last index that was returned, not next one that should be returned */
- int index; /* pointing at last index that was returned, not next one that should be returned */
+ int n_cascades;
+ int *cascade_index; /* each one points at last index that was returned, */
+ /* not next one that should be returned */
};
struct _GtkStyleProviderData
gtk_style_cascade_iter_next (GtkStyleCascade *cascade,
GtkStyleCascadeIter *iter)
{
- if (iter->parent_index > 0)
- {
- if (iter->index > 0)
- {
- GtkStyleProviderData *data, *parent_data;
+ GtkStyleCascade *cas;
+ int ix, highest_priority_index = 0;
+ GtkStyleProviderData *highest_priority_data = NULL;
- data = &g_array_index (cascade->providers, GtkStyleProviderData, iter->index - 1);
- parent_data = &g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index - 1);
+ for (cas = cascade, ix = 0; ix < iter->n_cascades; cas = cas->parent, ix++)
+ {
+ if (iter->cascade_index[ix] <= 0)
+ continue;
- if (data->priority >= parent_data->priority)
- {
- iter->index--;
- return data->provider;
- }
- else
- {
- iter->parent_index--;
- return parent_data->provider;
- }
- }
- else
+ GtkStyleProviderData *data = &g_array_index (cas->providers,
+ GtkStyleProviderData,
+ iter->cascade_index[ix] - 1);
+ if (highest_priority_data == NULL || data->priority > highest_priority_data->priority)
{
- iter->parent_index--;
- return g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index).provider;
+ highest_priority_index = ix;
+ highest_priority_data = data;
}
}
- else
+
+ if (highest_priority_data != NULL)
{
- if (iter->index > 0)
- {
- iter->index--;
- return g_array_index (cascade->providers, GtkStyleProviderData, iter->index).provider;
- }
- else
- {
- return NULL;
- }
+ iter->cascade_index[highest_priority_index]--;
+ return highest_priority_data->provider;
}
+ return NULL;
}
static GtkStyleProvider *
gtk_style_cascade_iter_init (GtkStyleCascade *cascade,
GtkStyleCascadeIter *iter)
{
- iter->parent_index = cascade->parent ? cascade->parent->providers->len : 0;
- iter->index = cascade->providers->len;
+ GtkStyleCascade *cas = cascade;
+ int ix;
+
+ iter->n_cascades = 1;
+ while ((cas = cas->parent) != NULL)
+ iter->n_cascades++;
+
+ iter->cascade_index = g_new (int, iter->n_cascades);
+ for (cas = cascade, ix = 0; ix < iter->n_cascades; cas = cas->parent, ix++)
+ iter->cascade_index[ix] = cas->providers->len;
return gtk_style_cascade_iter_next (cascade, iter);
}
+static void
+gtk_style_cascade_iter_clear (GtkStyleCascadeIter *iter)
+{
+ g_free (iter->cascade_index);
+}
+
static gboolean
gtk_style_cascade_get_style_property (GtkStyleProvider *provider,
GtkWidgetPath *path,
state,
pspec,
value))
- return TRUE;
+ {
+ gtk_style_cascade_iter_clear (&iter);
+ return TRUE;
+ }
}
+ gtk_style_cascade_iter_clear (&iter);
return FALSE;
}
settings = _gtk_style_provider_private_get_settings (GTK_STYLE_PROVIDER_PRIVATE (item));
if (settings)
- return settings;
+ {
+ gtk_style_cascade_iter_clear (&iter);
+ return settings;
+ }
}
+ gtk_style_cascade_iter_clear (&iter);
return NULL;
}
{
color = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (item), name);
if (color)
- return color;
+ {
+ gtk_style_cascade_iter_clear (&iter);
+ return color;
+ }
}
else
{
}
}
+ gtk_style_cascade_iter_clear (&iter);
return NULL;
}
keyframes = _gtk_style_provider_private_get_keyframes (GTK_STYLE_PROVIDER_PRIVATE (item), name);
if (keyframes)
- return keyframes;
+ {
+ gtk_style_cascade_iter_clear (&iter);
+ return keyframes;
+ }
}
+ gtk_style_cascade_iter_clear (&iter);
return NULL;
}
g_warn_if_reached ();
}
}
+ gtk_style_cascade_iter_clear (&iter);
}
static void
{
gtk_internal_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
gtk_internal_return_if_fail (parent == NULL || GTK_IS_STYLE_CASCADE (parent));
- if (parent)
- gtk_internal_return_if_fail (parent->parent == NULL);
if (cascade->parent == parent)
return;
#include <gtk/gtk.h>
+typedef struct {
+ GtkStyleContext *context;
+ GtkCssProvider *blue_provider;
+ GtkCssProvider *red_provider;
+ GtkCssProvider *green_provider;
+} PrioritiesFixture;
+
static void
test_parse_selectors (void)
{
g_object_unref (context);
}
+static void
+test_style_priorities_setup (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ f->blue_provider = gtk_css_provider_new ();
+ f->red_provider = gtk_css_provider_new ();
+ f->green_provider = gtk_css_provider_new ();
+ f->context = gtk_style_context_new ();
+ GtkWidgetPath *path = gtk_widget_path_new ();
+
+ gtk_css_provider_load_from_data (f->blue_provider, "* { color: blue; }", -1, &error);
+ g_assert_no_error (error);
+ gtk_css_provider_load_from_data (f->red_provider, "* { color: red; }", -1, &error);
+ g_assert_no_error (error);
+ gtk_css_provider_load_from_data (f->green_provider, "* { color: green; }", -1, &error);
+ g_assert_no_error (error);
+
+ gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
+ gtk_style_context_set_path (f->context, path);
+
+ gtk_widget_path_free (path);
+}
+
+static void
+test_style_priorities_teardown (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ g_object_unref (f->blue_provider);
+ g_object_unref (f->red_provider);
+ g_object_unref (f->green_provider);
+ g_object_unref (f->context);
+}
+
+static void
+test_style_priorities_equal (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ /* When style providers are added to the screen as well as the style context
+ the one specific to the style context should take priority */
+ gdk_rgba_parse (&ref_color, "red");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_screen_only (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ gdk_rgba_parse (&ref_color, "blue");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_context_only (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ gdk_rgba_parse (&ref_color, "red");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_screen_higher (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ gdk_rgba_parse (&ref_color, "blue");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_context_higher (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+ gdk_rgba_parse (&ref_color, "red");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_two_screen (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+ gdk_rgba_parse (&ref_color, "red");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_two_context (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+ gdk_rgba_parse (&ref_color, "red");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_three_screen_higher (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->green_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+ gdk_rgba_parse (&ref_color, "green");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_three_context_higher (PrioritiesFixture *f,
+ gconstpointer unused)
+{
+ GdkRGBA color, ref_color;
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (f->blue_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->green_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+ gdk_rgba_parse (&ref_color, "green");
+ gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+ &color);
+
+ g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
int
main (int argc, char *argv[])
{
g_test_add_func ("/style/widget-path-parent", test_widget_path_parent);
g_test_add_func ("/style/classes", test_style_classes);
+#define ADD_PRIORITIES_TEST(path, func) \
+ g_test_add ("/style/priorities/" path, PrioritiesFixture, NULL, test_style_priorities_setup, \
+ (func), test_style_priorities_teardown)
+
+ ADD_PRIORITIES_TEST ("equal", test_style_priorities_equal);
+ ADD_PRIORITIES_TEST ("screen-only", test_style_priorities_screen_only);
+ ADD_PRIORITIES_TEST ("context-only", test_style_priorities_context_only);
+ ADD_PRIORITIES_TEST ("screen-higher", test_style_priorities_screen_higher);
+ ADD_PRIORITIES_TEST ("context-higher", test_style_priorities_context_higher);
+ ADD_PRIORITIES_TEST ("two-screen", test_style_priorities_two_screen);
+ ADD_PRIORITIES_TEST ("two-context", test_style_priorities_two_context);
+ ADD_PRIORITIES_TEST ("three-screen-higher", test_style_priorities_three_screen_higher);
+ ADD_PRIORITIES_TEST ("three-context-higher", test_style_priorities_three_context_higher);
+
+#undef ADD_PRIORITIES_TEST
+
return g_test_run ();
}